{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tutorial 06: Networks from OpenStreetMap\n",
    "\n",
    "In this tutorial, we discuss how networks that have been imported from OpenStreetMap can be integrated and run in Flow. This will all be presented via the Bay Bridge network, seen in the figure below. Networks from OpenStreetMap are commonly used in many traffic simulators for the purposes of replicating traffic in realistic traffic geometries. This is true in both SUMO and Aimsun (which are both supported in Flow), with each supporting several techniques for importing such network files. This process is further simplified and abstracted in Flow, with users simply required to specify the path to the osm file in order to simulate traffic in the network.\n",
    "\n",
    "\n",
    "<img src=\"img/bay_bridge_osm.png\" width=750>\n",
    "<center> **Figure 1**: Snapshot of the Bay Bridge from OpenStreetMap </center>\n",
    "\n",
    "Before we begin, let us import all relevant Flow parameters as we have done for previous tutorials. If you are unfamiliar with these parameters, you are encouraged to review tutorial 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# the TestEnv environment is used to simply simulate the network\n",
    "from flow.envs import TestEnv\n",
    "\n",
    "# the Experiment class is used for running simulations\n",
    "from flow.core.experiment import Experiment\n",
    "\n",
    "# all other imports are standard\n",
    "from flow.core.params import VehicleParams\n",
    "from flow.core.params import NetParams\n",
    "from flow.core.params import InitialConfig\n",
    "from flow.core.params import EnvParams\n",
    "from flow.core.params import SumoParams"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Running a Default Simulation\n",
    "\n",
    "In order to create a network object in Flow with network features depicted from OpenStreetMap, we will use the base `Network` class. This class can sufficiently support the generation of any .osm file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from flow.networks import Network"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In order to recreate the network features of a specific osm file, the path to the osm file must be specified in `NetParams`. For this example, we will use an osm file extracted from the section of the Bay Bridge as depicted in Figure 1.\n",
    "\n",
    "In order to specify the path to the osm file, simply fill in the `osm_path` attribute with the path to the .osm file as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "net_params = NetParams(\n",
    "    osm_path='networks/bay_bridge.osm'\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next, we create all other parameters as we have in tutorials 1 and 2. For this example, we will assume a total of 1000 are uniformly spread across the Bay Bridge. Once again, if the choice of parameters is unclear, you are encouraged to review Tutorial 1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create the remainding parameters\n",
    "env_params = EnvParams()\n",
    "sim_params = SumoParams(render=True)\n",
    "initial_config = InitialConfig()\n",
    "vehicles = VehicleParams()\n",
    "vehicles.add('human', num_vehicles=100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are finally ready to test our network in simulation. In order to do so, we create an `Experiment` object and run the simulation for a number of steps. This is done in the cell below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_params = dict(\n",
    "    exp_tag='bay_bridge',\n",
    "    env_name=TestEnv,\n",
    "    network=Network,\n",
    "    simulator='traci',\n",
    "    sim=sim_params,\n",
    "    env=env_params,\n",
    "    net=net_params,\n",
    "    veh=vehicles,\n",
    "    initial=initial_config,\n",
    ")\n",
    "\n",
    "# number of time steps\n",
    "flow_params['env'].horizon = 1000\n",
    "exp = Experiment(flow_params)\n",
    "\n",
    "# run the sumo simulation\n",
    "_ = exp.run(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. Customizing the Network\n",
    "\n",
    "While the above example does allow you to view the network within Flow, the simulation is limited for two reasons. For one, vehicles are placed on all edges within the network; if we wished to simulate traffic solely on the on the bridge and do not care about the artireols, for instance, this would result in unnecessary computational burdens. Next, as you may have noticed if you ran the above example to completion, routes in the base network class are defaulted to consist of the vehicles' current edges only, meaning that vehicles exit the network as soon as they reach the end of the edge they are originated on. In the next subsections, we discuss how the network can be modified to resolve these issues.\n",
    "\n",
    "### 2.1 Specifying Traversable Edges\n",
    "\n",
    "In order to limit the edges vehicles are placed on to the road sections edges corresponding to the westbound Bay Bridge, we define an `EDGES_DISTRIBUTION` variable. This variable specifies the names of the edges within the network that vehicles are permitted to originated in, and is assigned to the network via the `edges_distribution` component of the `InitialConfig` input parameter, as seen in the code snippet below. Note that the names of the edges can be identified from the .osm file or by right clicking on specific edges from the SUMO gui (see the figure below).\n",
    "\n",
    "<img src=\"img/osm_edge_name.png\" width=600>\n",
    "<center> **Figure 2**: Name of an edge from SUMO </center>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# we define an EDGES_DISTRIBUTION variable with the edges within \n",
    "# the westbound Bay Bridge \n",
    "EDGES_DISTRIBUTION = [\n",
    "    \"11197898\",\n",
    "    \"123741311\", \n",
    "    \"123741303\",\n",
    "    \"90077193#0\",\n",
    "    \"90077193#1\", \n",
    "    \"340686922\", \n",
    "    \"236348366\", \n",
    "    \"340686911#0\",\n",
    "    \"340686911#1\",\n",
    "    \"340686911#2\",\n",
    "    \"340686911#3\",\n",
    "    \"236348361\", \n",
    "    \"236348360#0\", \n",
    "    \"236348360#1\"\n",
    "]\n",
    "\n",
    "# the above variable is added to initial_config\n",
    "new_initial_config = InitialConfig(\n",
    "    edges_distribution=EDGES_DISTRIBUTION\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 Creating Custom Routes\n",
    "\n",
    "Next, we choose to specify the routes of vehicles so that they can traverse the entire Bay Bridge, instead of the only the edge they are currently on. In order to this, we create a new network class that inherits all its properties from `Network` and simply redefine the routes by modifying the `specify_routes` variable. This method was originally introduced in Tutorial 07: Creating Custom Network. The new network class looks as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# we create a new network class to specify the expected routes\n",
    "class BayBridgeOSMNetwork(Network):\n",
    "\n",
    "    def specify_routes(self, net_params):\n",
    "        return {\n",
    "            \"11197898\": [\n",
    "                \"11197898\", \"123741311\", \"123741303\", \"90077193#0\", \"90077193#1\", \n",
    "                \"340686922\", \"236348366\", \"340686911#0\", \"340686911#1\",\n",
    "                \"340686911#2\", \"340686911#3\", \"236348361\", \"236348360#0\", \"236348360#1\",\n",
    "            ],\n",
    "            \"123741311\": [\n",
    "                \"123741311\", \"123741303\", \"90077193#0\", \"90077193#1\", \"340686922\", \n",
    "                \"236348366\", \"340686911#0\", \"340686911#1\", \"340686911#2\",\n",
    "                \"340686911#3\", \"236348361\", \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"123741303\": [\n",
    "                \"123741303\", \"90077193#0\", \"90077193#1\", \"340686922\", \"236348366\",\n",
    "                \"340686911#0\", \"340686911#1\", \"340686911#2\", \"340686911#3\", \"236348361\",\n",
    "                \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"90077193#0\": [\n",
    "                \"90077193#0\", \"90077193#1\", \"340686922\", \"236348366\", \"340686911#0\",\n",
    "                \"340686911#1\", \"340686911#2\", \"340686911#3\", \"236348361\", \"236348360#0\",\n",
    "                \"236348360#1\"\n",
    "            ],\n",
    "            \"90077193#1\": [\n",
    "                \"90077193#1\", \"340686922\", \"236348366\", \"340686911#0\", \"340686911#1\",\n",
    "                \"340686911#2\", \"340686911#3\", \"236348361\", \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"340686922\": [\n",
    "                \"340686922\", \"236348366\", \"340686911#0\", \"340686911#1\", \"340686911#2\",\n",
    "                \"340686911#3\", \"236348361\", \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"236348366\": [\n",
    "                \"236348366\", \"340686911#0\", \"340686911#1\", \"340686911#2\", \"340686911#3\",\n",
    "                \"236348361\", \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"340686911#0\": [\n",
    "                \"340686911#0\", \"340686911#1\", \"340686911#2\", \"340686911#3\", \"236348361\",\n",
    "                \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"340686911#1\": [\n",
    "                \"340686911#1\", \"340686911#2\", \"340686911#3\", \"236348361\", \"236348360#0\",\n",
    "                \"236348360#1\"\n",
    "            ],\n",
    "            \"340686911#2\": [\n",
    "                \"340686911#2\", \"340686911#3\", \"236348361\", \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"340686911#3\": [\n",
    "                \"340686911#3\", \"236348361\", \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"236348361\": [\n",
    "                \"236348361\", \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"236348360#0\": [\n",
    "                \"236348360#0\", \"236348360#1\"\n",
    "            ],\n",
    "            \"236348360#1\": [\n",
    "                \"236348360#1\"\n",
    "            ]\n",
    "        }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3 Rerunning the Simulation\n",
    "\n",
    "We are now ready to rerun the simulation with fully defined vehicle routes and a limited number of traversable edges. If we run the cell below, we can see the new simulation in action."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "flow_params = dict(\n",
    "    exp_tag='bay_bridge',\n",
    "    env_name=TestEnv,\n",
    "    network=BayBridgeOSMNetwork,\n",
    "    simulator='traci',\n",
    "    sim=sim_params,\n",
    "    env=env_params,\n",
    "    net=net_params,\n",
    "    veh=vehicles,\n",
    "    initial=new_initial_config,\n",
    ")\n",
    "\n",
    "# number of time steps\n",
    "flow_params['env'].horizon = 10000\n",
    "exp = Experiment(flow_params)\n",
    "\n",
    "# run the sumo simulation\n",
    "_ = exp.run(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Other Tips\n",
    "\n",
    "This tutorial introduces how to incorporate OpenStreetMap files in Flow. This feature, however, does not negate other features that are introduced in other tutorials and documentation. For example, if you would like to not have vehicles be originated side-by-side within a network, this can still be done by specifying a \"random\" spacing for vehicles as follows:\n",
    "\n",
    "    initial_config = InitialConfig(\n",
    "        spacing=\"random\",\n",
    "        edges_distribution=EDGES_DISTRIBUTION\n",
    "    )\n",
    "\n",
    "In addition, inflows of vehicles can be added to networks imported from OpenStreetMap as they are for any other network (see the tutorial on adding inflows for more on this)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
